package com.hzw.saas.web.app.rss.controller;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.hzw.saas.api.rss.ILibraryCatalogService;
import com.hzw.saas.api.rss.ILibraryEsService;
import com.hzw.saas.api.rss.ILibraryService;
import com.hzw.saas.api.rss.bo.LibraryBO;
import com.hzw.saas.api.rss.bo.LibraryCatalogBO;
import com.hzw.saas.api.rss.bo.LibraryNoticeBO;
import com.hzw.saas.api.rss.query.LibrarySearchQuery;
import com.hzw.saas.api.storage.IResourceFileService;
import com.hzw.saas.common.config.annotation.SysLog;
import com.hzw.saas.common.config.util.AssertUtil;
import com.hzw.saas.common.config.util.PageParam;
import com.hzw.saas.common.config.util.PageUtils;
import com.hzw.saas.common.security.utils.SecurityUtils;
import com.hzw.saas.common.util.MapperUtil;
import com.hzw.saas.common.util.SnowFlakeUtil;
import com.hzw.saas.common.util.enums.AssertEnum;
import com.hzw.saas.service.rss.dao.LibraryElasticRepository;
import com.hzw.saas.service.rss.model.LibraryNotice;
import com.hzw.saas.service.rss.parse.PDFParser;
import com.hzw.saas.service.rss.service.LibraryServiceImpl;
import com.hzw.saas.web.app.rss.dto.LibraryCatalogDTO;
import com.hzw.saas.web.app.rss.dto.LibraryDTO;
import com.hzw.saas.web.app.rss.dto.LibraryMetaDTO;
import com.hzw.saas.web.app.rss.param.LibraryParam;
import com.hzw.saas.web.app.rss.param.LibrarySearchParam;
import com.hzw.saas.web.app.rss.param.LibraryTreeParam;
import com.hzw.saas.web.app.rss.param.LibraryUpdateParam;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiOperationSort;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Controller
@RequiredArgsConstructor
@Api(tags = "文献期刊/我的文献")
@RequestMapping("/library")
public class LibraryController {

    private final ILibraryService libraryService;
    private final ILibraryCatalogService libraryTreeService;
    private final ILibraryEsService searchService;
    private final IResourceFileService resourceFileService;

    @Autowired
    private LibraryElasticRepository libraryElasticRepository;

    @ApiOperationSort(0)
    @GetMapping("/{libraryId}")
    @SysLog(operation = "获取文献详细信息")
    @ApiOperation(value = "获取文献详细信息")
    public ResponseEntity<LibraryBO> getLibraryInfo(@PathVariable String libraryId) {
        return ResponseEntity.ok(MapperUtil.nf().map(((LibraryServiceImpl) libraryService).getById(libraryId), LibraryBO.class));
    }

    @ApiOperationSort(1)
    @PostMapping("/")
    @SysLog(operation = "新增文献库")
    @ApiOperation(value = "新增文献库")
    public ResponseEntity<LibraryBO> addLibrary(@RequestBody @Valid LibraryParam libraryParam) {
        LibraryBO libraryBO = MapperUtil.nf().map(libraryParam, LibraryBO.class);
        libraryBO.setArticleId(SnowFlakeUtil.nextIdStr());
        libraryBO.setType(0); // 普通文献
        libraryBO.setCreatorId(SecurityUtils.getUserId()); // 设置创建人ID
        // fileId
        String fileId = libraryBO.getDownloadUrl();
        if (StrUtil.isNotBlank(fileId) && StrUtil.isBlank(libraryBO.getResourceMd5())) {
            File file = resourceFileService.getFileData(fileId, AssertEnum.IGNORE);
            if (FileUtil.exist(file)) {
                String resourceMd5 = SecureUtil.md5(file);
                libraryBO.setResourceMd5(resourceMd5);
            }
        }
       AssertUtil.assertThrow("文献资源不存在", StrUtil.isBlank(libraryBO.getResourceMd5()));
        ArrayList<LibraryBO> libraryBOS = new ArrayList<>();
        libraryBOS.add(libraryBO);
        List<LibraryNotice> libraryNotices = changeToNotice(libraryBOS);
        libraryElasticRepository.saveAll(libraryNotices);
        return ResponseEntity.ok(libraryService.addArticle(libraryBO));
    }

    @ApiOperationSort(2)
    @PutMapping("/")
    @SysLog(operation = "修改文献库")
    @ApiOperation(value = "修改文献库")
    public ResponseEntity<Void> updateLibrary(@RequestBody @Valid LibraryUpdateParam libraryParam) {
        LibraryBO libraryBO = MapperUtil.nf().map(libraryParam, LibraryBO.class);
        if (libraryBO.getCreatorId() == null || libraryBO.getCreatorId().equals("")){
            libraryBO.setCreatorId(SecurityUtils.getUserId());
        }
        libraryService.updateArticle(libraryBO);
        libraryElasticRepository.deleteById(libraryParam.getPid());
        ArrayList<LibraryBO> libraryBOS = new ArrayList<>();
        libraryBOS.add(libraryBO);
        List<LibraryNotice> libraryNotices = changeToNotice(libraryBOS);
        libraryNotices.forEach(libraryNotice -> {
            libraryNotice.setPid(libraryParam.getPid());
            if (libraryParam.getLibraryCatalogId()!= null && !libraryParam.getLibraryCatalogId().equals("")){
                libraryNotice.setTreeNode(libraryParam.getLibraryCatalogId());
            }
        });
        libraryElasticRepository.saveAll(libraryNotices);
        return ResponseEntity.ok().build();
    }

    @ApiOperationSort(3)
    @DeleteMapping("/{pid}")
    @SysLog(operation = "删除文献库")
    @ApiOperation(value = "删除文献库")
    public ResponseEntity<Void> deleteLibrary(@PathVariable("pid") String pid) {
        LibraryBO byPid = libraryService.getByPid(pid);
        libraryService.deleteArticle(pid);
        if (byPid != null){
            libraryElasticRepository.deleteById(pid);
        }
        return ResponseEntity.ok().build();
    }

    @ApiOperationSort(4)
    @DeleteMapping("/batch")
    @SysLog(operation = "批量删除文献库")
    @ApiOperation(value = "批量删除文献库")
    public ResponseEntity<Void> deleteBatchLibrary(@RequestBody List<String> pids) {

        List<LibraryBO> byArticleIds = libraryService.getByArticleIds(pids);
        if (CollectionUtil.isNotEmpty(byArticleIds)){
            List<String> collect = byArticleIds.stream().map(LibraryBO::getDownloadUrl).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(collect)){
                resourceFileService.deleteFiles(collect);
            }
            libraryService.deleteBatch(collect);
        }
        if (CollectionUtil.isNotEmpty(pids)){
            List<LibraryBO> articleIds = libraryService.getAriticleIds(pids);
            Iterable<LibraryNotice> allById = libraryElasticRepository.findAllById(pids);
            libraryElasticRepository.deleteAll(allById);
            List<String> collect = articleIds.stream().map(LibraryBO::getPid).collect(Collectors.toList());
            libraryService.deleteBatch(collect);
        }
        return ResponseEntity.ok().build();
    }

    @ApiOperationSort(5)
    @GetMapping("/")
    @SysLog(operation = "分页查询文献库")
    @ApiOperation(value = "分页查询文献库")
    public ResponseEntity<IPage<LibraryDTO>> searchLibrary(@ApiParam("分页参数") PageParam pageParam,
                                                           @RequestParam(required = false) @ApiParam("文献分类ID") String catalogId,
                                                           @RequestParam(required = false) @ApiParam("文献类型") Integer type) {
        IPage<LibraryBO> libraryBOIPage = libraryService.list(pageParam, SecurityUtils.getUser().getUserId(), catalogId, type);
        List<LibraryBO> records = libraryBOIPage.getRecords();
        if (CollectionUtil.isEmpty(records)) {
            return ResponseEntity.ok(new Page<>());
        }
        records.forEach(libraryBO -> {
            if (StrUtil.isBlank(libraryBO.getAuthor())) {
                return;
            }
            libraryBO.setAuthors(Arrays.stream(libraryBO.getAuthor().split(StrUtil.COMMA)).map(String::trim).collect(Collectors.toList()));
        });
        IPage<LibraryDTO> convert = PageUtils.convert(libraryBOIPage, LibraryDTO.class);
        return ResponseEntity.ok(convert);
    }

    @ApiOperationSort(6)
    @PostMapping("/search")
    @SysLog(operation = "检索文献库")
    @ApiOperation(value = "检索文献库")
    public ResponseEntity<IPage<LibraryNoticeBO>> searchLibrary(@RequestBody LibrarySearchParam librarySearchParam) {
        LibrarySearchQuery librarySearchQuery = MapperUtil.nf().map(librarySearchParam, LibrarySearchQuery.class);
        librarySearchQuery.setCreatorIds(Collections.singletonList(SecurityUtils.getUserId()));
        Page<LibraryNoticeBO> libraryNoticeBOPage = searchService.searchLibrary(librarySearchQuery);
        List<LibraryNoticeBO> libraryNoticeBOS = libraryNoticeBOPage.getRecords();
        if (CollectionUtil.isNotEmpty(libraryNoticeBOS)){
            List<String> collect = libraryNoticeBOS.stream().map(LibraryNoticeBO::getPid).collect(Collectors.toList());
            List<LibraryBO> byIds = libraryService.getAriticleIds(collect);
            List<String> collect1 = byIds.stream().map(LibraryBO::getLibraryCatalogId).collect(Collectors.toList());
            List<LibraryCatalogBO> byIds1 = libraryTreeService.getByIds(collect1);
            HashMap<String, String> stringStringHashMap = new HashMap<>();
            byIds.forEach(libraryBO -> {
                byIds1.forEach(libraryCatalogBO -> {
                    if (libraryBO.getLibraryCatalogId().equals(libraryCatalogBO.getPid())){
                        stringStringHashMap.put(libraryBO.getArticleId(),libraryCatalogBO.getName());
                    }
                });
            });
            libraryNoticeBOS.forEach(libraryNoticeBO -> {
                // 设置作者信息
                List<String> authors = libraryNoticeBO.getAuthors();
                if (CollectionUtil.isNotEmpty(authors)) {
                    String author = String.join(",", authors);
                    libraryNoticeBO.setAuthor(author);
                }
                // 设置节点名称
                String libraryCatalogId = libraryNoticeBO.getLibraryCatalogId();
                LibraryCatalogBO libraryCatalogBO = libraryTreeService.findById(libraryCatalogId);
                if (Objects.nonNull(libraryCatalogBO)) {
                    libraryNoticeBO.setLibraryCatalogName(libraryCatalogBO.getName());
                }
                byIds.forEach(libraryBO -> {
                    libraryNoticeBO.setType(libraryBO.getType());
                    libraryNoticeBO.setLibraryCatalogId(libraryBO.getLibraryCatalogId());
                });

                stringStringHashMap.forEach((s, s2) -> {
                    if (libraryNoticeBO.getPid().equals(s)){
                        libraryNoticeBO.setLibraryCatalogName(s2);
                    }
                });
            });

        }
        return ResponseEntity.ok(libraryNoticeBOPage);
    }

    @ApiOperationSort(7)
    @PostMapping("/parsing/{fileId}")
    @SysLog(operation = "文献元数据解析")
    @ApiOperation(value = "文献元数据解析", notes = "指定fileId，该资源是特定格式的PDF文件")
    public ResponseEntity<LibraryMetaDTO> parsingPDF(@PathVariable String fileId) {
        File file = resourceFileService.getFileData(fileId, AssertEnum.IGNORE);
//        // 判断资源是否存在
        String resourceMd5 = SecureUtil.md5(file);
        boolean exist = libraryService.existLibrary(SecurityUtils.getUserId(), resourceMd5);
        if (exist) {
            // 解析元数据如果存在，则直接删除
            resourceFileService.deleteFile(fileId);
            return ResponseEntity.ok(new LibraryMetaDTO().setState(1));
        }
        if (!FileUtil.exist(file)) {
            // 资源不存在
            return ResponseEntity.ok(new LibraryMetaDTO().setState(2));
        }
        Map<String, Object> resultMap = PDFParser.getInstance().getRss(file);
        LibraryMetaDTO libraryMetaDTO = MapperUtil.nf().map(resultMap, LibraryMetaDTO.class);
        libraryMetaDTO.setResourceMd5(resourceMd5);
        return ResponseEntity.ok(libraryMetaDTO);
    }

    @ApiOperationSort(8)
    @PostMapping("/catalog")
    @SysLog(operation = "文献分类新增")
    @ApiOperation(value = "文献分类新增")
    public ResponseEntity<Void> addLibraryTree(@RequestBody LibraryTreeParam libraryTreeParam) {
        LibraryCatalogBO map = MapperUtil.nf().map(libraryTreeParam, LibraryCatalogBO.class);
        libraryTreeService.addCatalog(map);
        return ResponseEntity.ok().build();
    }

    @ApiOperationSort(9)
    @PutMapping("/catalog")
    @SysLog(operation = "文献分类修改")
    @ApiOperation(value = "文献分类修改")
    public ResponseEntity<Void> updateLibraryTree(@RequestBody LibraryTreeParam libraryTreeParam) {
        LibraryCatalogBO map = MapperUtil.nf().map(libraryTreeParam, LibraryCatalogBO.class);
        libraryTreeService.updateCatalog(map);
        return ResponseEntity.ok().build();
    }


    @ApiOperationSort(10)
    @DeleteMapping("/catalog/{catalogId}")
    @SysLog(operation = "文献分类删除")
    @ApiOperation(value = "文献分类删除")
    public ResponseEntity<Void> deleteLibraryTree(@PathVariable("catalogId") String catalogId) {
        libraryTreeService.deleteCatalog(catalogId);
        return ResponseEntity.ok().build();
    }

    @ApiOperationSort(11)
    @GetMapping("/catalog")
    @SysLog(operation = "查询用户的文献分类")
    @ApiOperation(value = "查询用户的文献分类")
    public ResponseEntity<List<LibraryCatalogDTO>> findUserTree() {
        List<LibraryCatalogBO> userCatalogs = libraryTreeService.findUserCatalog(SecurityUtils.getUserId());
        boolean history = libraryTreeService.findHistory(SecurityUtils.getUserId());
        if (CollectionUtil.isEmpty(userCatalogs) && !history) {
            userCatalogs = libraryTreeService.initCatalog(SecurityUtils.getUserId());
        }
        userCatalogs.forEach(userCatalogParent -> {
            List<LibraryCatalogBO> libraryCatalogBOS = userCatalogParent.getLibraryCatalogBOS();
            if (CollectionUtil.isEmpty(libraryCatalogBOS)) {
                return;
            }
            libraryCatalogBOS.forEach(userCatalog -> {
            int count = libraryService.libraryCount(SecurityUtils.getUserId(), userCatalog.getPid());
                userCatalog.setCount(count);
            });
            userCatalogParent.setCount(libraryCatalogBOS.stream().mapToInt(LibraryCatalogBO::getCount).sum());
        });
        return ResponseEntity.ok(MapperUtil.nf().mapAsList(userCatalogs, LibraryCatalogDTO.class));
    }


    @ApiOperationSort(12)
    @GetMapping("/synchronization")
    @ApiOperation("收藏和上传数据同步es")
    public ResponseEntity<Void> synchronization(){
        List<LibraryBO> all = libraryService.findAll();
        log.info("同步前数据库的数据"+all);
        if (CollectionUtil.isNotEmpty(all)){
            log.debug("同步前数据库的数据共"+all.size()+"条数据");
            log.debug("主键为"+all.stream().map(LibraryBO::getPid).collect(Collectors.toList()));
            log.debug("文章id为"+all.stream().map(LibraryBO::getArticleId).collect(Collectors.toList()));
        }
        if (CollectionUtil.isEmpty(all)){
            return ResponseEntity.ok().build();
        }
        Iterable<LibraryNotice> libraryNotices = libraryElasticRepository.findAll();
        log.info("同步前es的数据"+libraryNotices);
        ArrayList<LibraryNotice> libraryNotices1 = Lists.newArrayList(libraryNotices);
        if (CollectionUtil.isNotEmpty(libraryNotices1)){
            ArrayList<LibraryBO> libraryBOS = new ArrayList<>();
            libraryNotices1.forEach(libraryNotice -> {
               all.forEach(libraryBO -> {
                   if (libraryBO.getArticleId().equals(libraryNotice.getPid())&&libraryBO.getCreatorId().equals(libraryNotice.getCreatorId())){
                       libraryBOS.add(libraryBO);
                   }
               });
           });
            if (CollectionUtil.isNotEmpty(libraryBOS)){
                all.removeAll(libraryBOS);
            }

        }
        libraryElasticRepository.saveAll(changeToNotice(all));
        Iterable<LibraryNotice> all1 = libraryElasticRepository.findAll();
        log.info("同步后es中的数据"+all1);
        return ResponseEntity.ok().build();
    }

    public List<LibraryNotice> changeToNotice(List<LibraryBO> list){
        if (CollectionUtil.isEmpty(list)){
            return new ArrayList<>();
        }
        list.forEach(libraryBO -> {
            if (libraryBO.getArticleId() == null || libraryBO.getArticleId().equals("")){
                libraryBO.setArticleId(SnowFlakeUtil.nextIdStr());
            }
        });
        libraryService.updateAll(list);
        ArrayList<LibraryNotice> libraryNotices = new ArrayList<>();
        list.forEach(libraryBO -> {
            LibraryNotice map = MapperUtil.nf().map(libraryBO, LibraryNotice.class);
            map.setTreeNode(libraryBO.getLibraryCatalogId());
            map.setPid(libraryBO.getArticleId());
            map.setType(libraryBO.getType());
            map.setCreatorId(SecurityUtils.getUserId());
            libraryNotices.add(map);
        });
        return libraryNotices;
    }
}
